using System;
using System.Net;
using System.Threading;
using System.Collections.Generic;
using System.Net.NetworkInformation;

namespace Publish.Services.SocketUdp
{
    /// <summary>
    /// 局域网搜索的方法
    /// </summary>
    public class LanSearch
    {
        #region Field

        /// <summary>
        /// IP最后一位的数字 递增用于局域网主机搜索
        /// </summary>
        private int ipIndex = 1;
        /// <summary>
        /// 标识  共享锁
        /// </summary>
        private object obj = new object();
        /// <summary>
        /// ip前面三位 C类地址的网路号
        /// </summary>
        private String netId = "";
        /// <summary>
        /// 主机字典
        /// </summary>
        private IDictionary<String, String> idictHost = new Dictionary<String, String>();
        /// <summary>
        /// 错误字典
        /// </summary>
        private IDictionary<String, String> idictError = new Dictionary<String, String>();

        /// <summary>
        /// 搜索完成的代理
        /// </summary>
        public delegate void OnSearchCompleteHandler(LanSearch sender, EventArgs e);
        /// <summary>
        /// 搜索完成的事件
        /// </summary>
        public event OnSearchCompleteHandler OnSearchComplete;

        #endregion

        #region Property

        /// <summary>
        /// 存放键值对的 主机字典  key=ip  value=host
        /// </summary>
        public IDictionary<String, String> IdictHost { get { return idictHost; } }

        /// <summary>
        /// 存放错误的键值对 主机字段 key=ip,value=host
        /// </summary>
        public IDictionary<String, String> IdictError { get { return idictError; } }

        #endregion

        #region Method

        #region 获取本机的IP列表 为考虑到有些主机装有多网卡 所以将会获取所有的网卡

        /// <summary>
        /// 获取本机的IP列表 为考虑到有些主机装有多网卡 所以将会获取所有的网卡
        /// </summary>
        /// <returns>返回IP信息列表</returns>
        private IPAddress[] GetLocalIpList()
        {
            String hostName = Dns.GetHostName();
            IPHostEntry ipEntry = Dns.GetHostEntry(hostName);
            return ipEntry.AddressList;
        }

        #endregion

        #region 局域网IP的搜索方法

        /// <summary>
        /// 局域网IP的搜索方法
        /// </summary>
        public void Search()
        {
            var localIp = GetLocalIpList()[2].ToString();
            netId = localIp.Substring(0, localIp.LastIndexOf('.'));
            var threadMethod = new ThreadStart(LanSearchThreadMethod);
            //开了多个线程 这里感觉不知道对不对
            var thread = new Thread(threadMethod) { Name = "t1" };
            thread.Start();
        }

        #endregion

        #region 搜索方法 多线程

        /// <summary>
        /// 搜索方法 多线程
        /// </summary>
        private void LanSearchThreadMethod()
        {
            lock (obj)
            {
                while (ipIndex < 255)
                {
                    Console.WriteLine(Thread.CurrentThread.Name);
                    IPAddress scanIp = IPAddress.Parse(Convert.ToString(netId + "." + (ipIndex++)));　//获得扫描IP地址 
                    Ping ping = new Ping();
                    ping.PingCompleted += new PingCompletedEventHandler(PingCompletedCallBack);//设置PingCompleted事件处理程序   
                    ping.SendAsync(scanIp, null);
                    Thread.Sleep(100);
                }

                //搜索完成 回调方法
                if (ipIndex >= 255)
                {
                    OnSearchComplete(this, new EventArgs());
                }
            }
        }

        #endregion

        #endregion

        #region Event

        #region ping完成的回调事件

        /// <summary>
        /// ping完成的回调事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PingCompletedCallBack(object sender, PingCompletedEventArgs e)
        {
            PingReply reply = e.Reply;
            if (e.Cancelled)
            {
                idictError.Add(reply.Address.ToString(), "Ping Canncel");
                //Console.WriteLine("Ping Canncel");
                return;
            }
            if (e.Error != null)
            {
                idictError.Add(reply.Address.ToString(), e.Error.Message);
                //Console.WriteLine(e.Error.Message);
                return;
            }

            //Console.WriteLine("state:"+reply.Status.ToString()+reply.Address.ToString());
            if (reply.Status == IPStatus.Success)
            {
                try
                {
                    //防止获取主机出错的时候  中断程序
                    IdictHost.Add(Dns.GetHostEntry(reply.Address).HostName, reply.Address.ToString());
                    //Console.WriteLine(Thread.CurrentThread.Name + ":" + reply.Address.ToString());
                }
                catch
                { }
            }
        }

        #endregion

        #endregion
    }
}
